home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / 8250.C next >
C/C++ Source or Header  |  1989-08-09  |  7KB  |  311 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "asy.h"
  5. #include "8250.h"
  6. #include "iface.h"
  7.  
  8. struct asy asy[ASY_MAX];
  9. unsigned nasy;
  10.  
  11. /* ASY interrupt handlers */
  12. extern void asy0vec(),asy1vec(),asy2vec(),asy3vec(),asy4vec(),asy5vec();
  13. void (*handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec,asy5vec};
  14.  
  15. /* Initialize asynch port "dev" */
  16. int
  17. asy_init(dev,arg1,arg2,bufsize)
  18. int16 dev;
  19. char *arg1,*arg2;    /* Attach args for address and vector */
  20. unsigned bufsize;
  21. {
  22.     register unsigned base;
  23.     register struct fifo *fp;
  24.     register struct asy *ap;
  25.     void (*getirq())();
  26.     char i_state;
  27.  
  28.     ap = &asy[dev];
  29.     ap->addr = htoi(arg1);
  30.     ap->vec = htoi(arg2);
  31.     /* Set up receiver FIFO */
  32.     fp = &ap->fifo;
  33.     if((fp->buf = malloc(bufsize)) == NULLCHAR){
  34.         printf("asy%d: No space for rx buffer\r\n",dev);
  35.         fflush(stdout);
  36.         return -1;
  37.     }
  38.     fp->bufsize = bufsize;
  39.     fp->wp = fp->rp = fp->buf;
  40.     fp->cnt = 0;
  41.  
  42.     base = ap->addr;
  43.  
  44.     /* Purge the receive data buffer */
  45.     (void)inportb(base+RBR);
  46.  
  47.     i_state = disable();
  48.  
  49.     /* Save original interrupt vector, mask state, control bits */
  50.     ap->save.vec = getirq(ap->vec);
  51.     ap->save.mask = getmask(ap->vec);
  52.     ap->save.lcr = inportb(base+LCR);
  53.     ap->save.ier = inportb(base+IER);
  54.     ap->save.mcr = inportb(base+MCR);
  55.  
  56.     /* save speed bytes */
  57.     setbit(base+LCR,LCR_DLAB);
  58.     ap->save.divl = inportb(base+DLL);
  59.     ap->save.divh = inportb(base+DLM);
  60.     clrbit(base+LCR,LCR_DLAB);
  61.  
  62.     /* Set interrupt vector to SIO handler */
  63.     setirq(ap->vec,handle[dev]);
  64.  
  65.     /* Set line control register: 8 bits, no parity */
  66.     outportb(base+LCR,(char)LCR_8BITS);
  67.  
  68.     /* Turn on receive interrupt enable in 8250, leave transmit
  69.      * and modem status interrupts turned off for now
  70.      */
  71.     outportb(base+IER,(char)IER_DAV);
  72.  
  73.     /* Set modem control register: assert DTR, RTS, turn on 8250
  74.      * master interrupt enable (connected to OUT2)
  75.      */
  76.     outportb(base+MCR,(char)(MCR_DTR|MCR_RTS|MCR_OUT2));
  77.  
  78.     /* Enable interrupt */
  79.     maskon(ap->vec);
  80.     restore(i_state);
  81.     return 0;
  82. }
  83. int
  84. asy_stop(iface)
  85. struct interface *iface;
  86. {
  87.     register unsigned base;
  88.     register struct asy *ap;
  89.     char i_state;
  90.  
  91.     ap = &asy[iface->dev];
  92.     base = ap->addr;
  93.  
  94.     /* Purge the receive data buffer */
  95.     (void)inportb(base+RBR);
  96.  
  97.     /* Restore original interrupt vector and 8259 mask state */
  98.     i_state = disable();
  99.     setirq(ap->vec,ap->save.vec);
  100.     if(ap->save.mask)
  101.         maskon(ap->vec);
  102.     else
  103.         maskoff(ap->vec);
  104.  
  105.     /* Restore speed regs */
  106.     setbit(base+LCR,LCR_DLAB);
  107.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  108.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  109.     clrbit(base+LCR,LCR_DLAB);
  110.  
  111.     /* Restore control regs */
  112.     outportb(base+LCR,ap->save.lcr);
  113.     outportb(base+IER,ap->save.ier);
  114.     outportb(base+MCR,ap->save.mcr);
  115.     restore(i_state);
  116. }
  117. /* Asynchronous line I/O control */
  118. asy_ioctl(interface,argc,argv)
  119. struct interface *interface;
  120. int argc;
  121. char *argv[];
  122. {
  123.     if(argc < 1){
  124.         printf("%d\r\n",asy[interface->dev].speed);
  125.         return 0;
  126.     }
  127.     return asy_speed(interface->dev,atoi(argv[0]));
  128. }
  129. /* Set asynch line speed */
  130. int
  131. asy_speed(dev,speed)
  132. int16 dev;
  133. int speed;
  134. {
  135.     register unsigned base;
  136.     register int divisor;
  137.     char i_state;
  138.  
  139.     if(speed == 0 || dev >= nasy)
  140.         return -1;
  141.     
  142.     base = asy[dev].addr;
  143.     asy[dev].speed = speed;
  144.  
  145.     divisor = BAUDCLK / (long)speed;
  146.  
  147.     i_state = disable();
  148.  
  149.     /* Purge the receive data buffer */
  150.     (void)inportb(base+RBR);
  151.  
  152.     /* Turn on divisor latch access bit */
  153.     setbit(base+LCR,LCR_DLAB);
  154.  
  155.     /* Load the two bytes of the register */
  156.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  157.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  158.  
  159.     /* Turn off divisor latch access bit */
  160.     clrbit(base+LCR,LCR_DLAB);
  161.  
  162.     restore(i_state);
  163.     return 0;
  164. }
  165.  
  166. /* Send a buffer to serial transmitter */
  167. asy_output(dev,buf,cnt)
  168. unsigned dev;
  169. char *buf;
  170. unsigned short cnt;
  171. {
  172.     register struct dma *dp;
  173.     unsigned base;
  174.     char i_state;
  175.  
  176.     if(dev >= nasy)
  177.         return;
  178.     base = asy[dev].addr;
  179.     dp = &asy[dev].dma;
  180.     i_state = disable();
  181.     if(dp->flags){
  182.         restore(i_state);
  183.         return;    /* Already busy */
  184.     }
  185.     dp->data = buf;
  186.     dp->cnt = cnt;
  187.     dp->flags = 1;
  188.     /* Enable transmitter buffer empty interrupt and simulate
  189.      * an interrupt; this will get things rolling.
  190.      */
  191.     setbit(base+IER,IER_TxE);
  192.     asytxint(dev);
  193.     restore(i_state);
  194. }
  195. /* Receive characters from asynch line
  196.  * Returns count of characters read
  197.  */
  198. int16
  199. asy_recv(dev,buf,cnt)
  200. int16 dev;
  201. char *buf;
  202. unsigned cnt;
  203. {
  204.     unsigned tot,n;
  205.     int kbread();
  206.     char i_state;
  207.     struct fifo *fp;
  208.  
  209.     fp = &asy[dev].fifo;
  210.     tot = 0;
  211.     /* Read from serial I/O input buffer */
  212.     i_state = disable();
  213.     for(;;){
  214.         n = min(cnt,fp->cnt);
  215.         if(n == 0)
  216.             break;
  217.         n = min(n,&fp->buf[fp->bufsize] - fp->rp);
  218.         memcpy(buf,fp->rp,n);
  219.         fp->rp += n;
  220.         if(fp->rp >= &fp->buf[fp->bufsize])
  221.             fp->rp = fp->buf;
  222.         fp->cnt -= n;
  223.         buf += n;
  224.         tot += n;
  225.         cnt -= n;
  226.     }
  227.     restore(i_state);
  228.     return tot;
  229.  
  230. }
  231. /* Interrupt handler for 8250 asynch chip */
  232. void
  233. asyint(dev)
  234. unsigned dev;
  235. {
  236.     register unsigned base;
  237.     register char iir;
  238.  
  239.     base = asy[dev].addr;
  240.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  241.         switch(iir & IIR_ID){
  242.         case IIR_RDA:    /* Receiver interrupt */
  243.             asyrxint(dev);
  244.             break;
  245.         case IIR_THRE:    /* Transmit interrupt */
  246.             asytxint(dev);
  247.             break;
  248.         }
  249.     }
  250. }
  251. /* Process 8250 receiver interrupts */
  252. static
  253. asyrxint(dev)
  254. unsigned dev;
  255. {
  256.     unsigned base;
  257.     register struct fifo *fp;
  258.     char c;
  259.  
  260.     base = asy[dev].addr;
  261.     fp = &asy[dev].fifo;
  262.     while(inportb(base+LSR) & LSR_DR){
  263.         c = inportb(base+RBR);
  264.         /* Process incoming data;
  265.          * If buffer is full, we have no choice but
  266.          * to drop the character
  267.          */
  268.         if(fp->cnt != fp->bufsize){
  269.             *fp->wp++ = c;
  270.             if(fp->wp == &fp->buf[fp->bufsize])
  271.                 /* Wrap around */
  272.                 fp->wp = fp->buf;
  273.             fp->cnt++;
  274.         }
  275.     }
  276. }
  277. /* Handle 8250 transmitter interrupts */
  278. static
  279. asytxint(dev)
  280. unsigned dev;
  281. {
  282.     register struct dma *dp;
  283.     register unsigned base;
  284.  
  285.     base = asy[dev].addr;
  286.     dp = &asy[dev].dma;
  287.     if(!dp->flags){
  288.         /* "Shouldn't happen", but disable transmit
  289.          * interrupts anyway
  290.          */
  291.         clrbit(base+IER,IER_TxE);
  292.         return;    /* Nothing to send */
  293.     }
  294.     while(inportb(base+LSR) & LSR_THRE){
  295.         outportb(base+THR,*dp->data++);
  296.         if(--dp->cnt == 0){
  297.             dp->flags = 0;
  298.             /* Disable transmit interrupts */
  299.             clrbit(base+IER,IER_TxE);
  300.             /* Call completion interrupt here */
  301.             break;
  302.         }
  303.     }
  304. }
  305. int
  306. stxrdy(dev)
  307. int16 dev;
  308. {
  309.     return(!asy[dev].dma.flags);
  310. }
  311.